using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;

namespace Microsoft.Samples
{
	/// <summary>
	/// Summary description for SolidClock.
	/// </summary>
	
	[Designer(typeof(SolidClockDesigner))]
	public class SolidClock : Control, IRegionControl
	{
		#region Fields
		// Property fields
		private bool addToFormRegion;
		private bool antiAlias;
		private ClockInterval clockInterval;
		private bool fillClock;
		private int intraArcPadding;
		private int outerArcThickness;

		// Interal fields
		private System.Windows.Forms.Timer timer;
		private DateTime currentTime;
		#endregion

		#region Constructor
		public SolidClock()
		{
			// Set controls styles
			this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);

			// Intialize property fields
			addToFormRegion = false	;
			antiAlias = true;
			clockInterval = ClockInterval.MinutesAndSeconds;
			fillClock = true;
			intraArcPadding = 7;
			outerArcThickness = 15;

			// Setup timer
			timer = new System.Windows.Forms.Timer();
			timer.Interval = 990;
			timer.Tick += new EventHandler(this.timer_Tick);
			timer.Enabled = true;

			// Set current time
			currentTime = DateTime.Now;
		}
		#endregion

		#region Properties
		// Proeprties
		[
		Category("Behavior"),
		DefaultValue(false),
		Description("This property interacts with the RegionBuilder component to control the shape of the parent Form")
		]
		public bool AddToFormRegion 
		{
			get 
			{
				return addToFormRegion;
			}
			set 
			{
				addToFormRegion = value;
			}
		}

		[
		Category("Appearance"),
		DefaultValue(true),
		Description("Controls whether the clock is drawn with antialiasing")
		]
		public bool AntiAlias 
		{
			get 
			{
				return antiAlias;
			}
			set 
			{
				antiAlias = value;
				Invalidate();
			}
		}

		[
		Category("Behavior"),
		DefaultValue(ClockInterval.MinutesAndSeconds),
		Description("Indicates whether the clock shows mintues and seconds or hours and minutes")
		]
		public ClockInterval ClockInterval 
		{
			get 
			{
				return clockInterval;
			}
			set 
			{
				clockInterval = value;
				Invalidate();
			}
		}

		[
		Category("Appearance"),
		DefaultValue(true),
		Description("Indicates wheter the clock bars are outlined or solid")
		]
		public bool FillClock 
		{
			get 
			{
				return fillClock;
			}
			set 
			{
				fillClock = value;
				Invalidate();
			}
		}

		[
		Category("Appearance"),
		DefaultValue(7),
		Description("Controls the amount of space between the inner pie and outer ring")
		]
		public int IntraArcPadding 
		{
			get 
			{
				return intraArcPadding;
			}
			set 
			{
				if (value < 0) 
				{
					throw new ArgumentOutOfRangeException("IntraArcPadding", value, "IntraArcPadding cannot be negative");
				}
				intraArcPadding = value;
				Invalidate();
			}
		}

		[
		Category("Appearance"),
		DefaultValue(15),
		Description("Controls the thickness of the outer ring")
		]
		public int OuterArcThickness 
		{
			get 
			{
				return outerArcThickness;
			}
			set 
			{
				if (value < 1) 
				{
					throw new ArgumentOutOfRangeException("OuterArcThickness", value, "OuterArcThickness cannot be less than 1");
				}
				outerArcThickness = value;
				Invalidate();
			}
		}
		#endregion

		#region Methods, EventHandlers, etc.
		private GraphicsPath MakePath() 
		{
			GraphicsPath path = new GraphicsPath();
			int smallInterval;

			// Layout members
			int outerArcPadding = (3 + outerArcThickness);
			int innerPiePadding = (3 + outerArcThickness + intraArcPadding);

			// Choose interval
			if (clockInterval == Microsoft.Samples.ClockInterval.MinutesAndSeconds) 
			{
				smallInterval = DateTime.Now.Second;
			}
			else 
			{
				smallInterval = DateTime.Now.Minute;
			}

			// Draw Minutes / Seconds

			if ((this.Width - (2 * outerArcPadding) > 0) && (this.Height - (2 * outerArcPadding) > 0))
			{
				path.StartFigure();
				path.AddArc(3, 3, this.Width - 6, this.Height - 6, 270 + ((smallInterval / 60f) * 360), -(smallInterval / 60f) * 360);
				path.AddArc(outerArcPadding, outerArcPadding, this.Width - (2 * outerArcPadding), this.Height - (2 * outerArcPadding), 270, (smallInterval / 60f) * 360);
				path.CloseFigure();
			}
		

			// Draw Hours / Minutes
			if ((this.Width - (2 * innerPiePadding) > 0) && (this.Height - (2 * innerPiePadding) > 0))
			{
				if (clockInterval == Microsoft.Samples.ClockInterval.MinutesAndSeconds) 
				{
					path.AddPie(innerPiePadding, innerPiePadding, this.Width - (2 * innerPiePadding), this.Height - (2 * innerPiePadding), 270, (DateTime.Now.Minute / 60f) * 360);
				}
				else 
				{
					path.AddPie(innerPiePadding, innerPiePadding, this.Width - (2 * innerPiePadding), this.Height - (2 * innerPiePadding), 270, ((DateTime.Now.Hour % 12) / 12f) * 360);
				}
			}
			
			return path;
		}

		Region IRegionControl.MakeRegion(Form parent) 
		{
			Region region = new Region(this.MakePath());

			int borderSize = (parent.Width - parent.ClientRectangle.Width) / 2;
			int titlebarSize = parent.Height - parent.ClientRectangle.Height - borderSize;
			region.Translate(this.Location.X + borderSize, this.Location.Y + titlebarSize);

			return region;
		}

		protected override void OnPaint(PaintEventArgs e) 
		{
			base.OnPaint(e);

			// Setup antialaising
			if (antiAlias) 
			{
				e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
			}

			// Draw background
			e.Graphics.FillRectangle(new SolidBrush(this.BackColor), e.Graphics.VisibleClipBounds);

			// Draw clock
			if (fillClock) 
			{
				e.Graphics.FillPath(new SolidBrush(this.ForeColor), this.MakePath());
			}
			else 
			{
				e.Graphics.DrawPath(new Pen(this.ForeColor), this.MakePath());
			}
		}

		private void timer_Tick(object sender, EventArgs e) 
		{
			if (clockInterval == ClockInterval.HoursAndMinutes) 
			{
				// If HoursAndMinutes, raise paint event every minute
				if ((currentTime.Minute <= DateTime.Now.Minute) || (currentTime.Minute == 59))
				{
					currentTime = DateTime.Now;
					this.Invalidate();
				}
			}
			else 
			{
				// If MinutesAndSeconds, raise paint event every second
				if ((currentTime.Second <= DateTime.Now.Second) || (currentTime.Second == 59)) 
				{
					currentTime = DateTime.Now;
					this.Invalidate();
				}
			}
		}
		#endregion
	}
}
